﻿using System;
using GeneticAlgorithms.Genomes;
using GeneticAlgorithms.Operators.Crossover;
using GeneticAlgorithms.Tests.Utils;
using GeneticAlgorithms.Tools;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace GeneticAlgorithms.Tests.Operators.Crossover
{
    [TestClass]
    public class SinglePointCrossoverTest
    {
        [TestMethod]
        public void TestCross()
        {
            int length = 17;
            int flipPos = 5;
            IGeneticRandomGenerator originalRnd = GeneticRandomGenerator.Default;
            Mock<IGeneticRandomGenerator> randomMock = new Mock<IGeneticRandomGenerator>();
            randomMock.Expect(r => r.Next(length)).Returns(flipPos);
            GeneticRandomGenerator.Default = randomMock.Object;
            CrossoverOperatorTestHelper<ArrayGenome<bool>, bool> helper =
                new CrossoverOperatorTestHelper<ArrayGenome<bool>, bool>();
            ArrayGenome<bool>[] parents = new ArrayGenome<bool>[2];
            parents[0] = helper.GetBoolGenome(length);
            parents[1] = helper.GetBoolGenome(length, false);
            ArrayGenome<bool>[] expected = new ArrayGenome<bool>[2];
            expected[0] = helper.GetBoolGenome(length, i => i < flipPos);
            expected[1] = helper.GetBoolGenome(length, i => i >= flipPos);
            ArrayGenome<bool>[] actual = new ArrayGenome<bool>[2];
            actual[0] = helper.GetBoolGenome(length);
            actual[1] = helper.GetBoolGenome(length);
            SinglePointCrossover<ArrayGenome<bool>, bool> target =
                new SinglePointCrossover<ArrayGenome<bool>, bool>();
            target.Cross(parents, actual);
            ExtraAssert.GenomeCollectionsMatch<ArrayGenome<bool>, bool>
                (expected, actual);
            GeneticRandomGenerator.Default = originalRnd;
        }

        [TestMethod]
        public void TestCardinalityCheckFails()
        {
            ArrayGenome<bool>[] parents = new ArrayGenome<bool>[2];
            ArrayGenome<bool>[] children = new ArrayGenome<bool>[3];
            SinglePointCrossover<ArrayGenome<bool>, bool> target =
                new SinglePointCrossover<ArrayGenome<bool>, bool>();
            ExtraAssert.MethodFails(
                () => target.Cross(parents, children),
                delegate(Exception exc)
                {
                    Assert.IsInstanceOfType(exc, typeof(ArgumentException));
                    StringAssert.Contains(exc.Message, "Wrong cardinality");
                }
            );
        }
    }
}
